import struct
import traceback
import typing

from .datatypes import *
from .logger import get_logger

CHARACTERISTIC_DEPOSIT_MAP = {
    XCPRecordLayout.Scalar_BOOLEAN: "Scalar_BOOLEAN",
    XCPRecordLayout.Scalar_UBYTE: "Scalar_UBYTE",
    XCPRecordLayout.Scalar_SBYTE: "Scalar_SBYTE",
    XCPRecordLayout.Scalar_UWORD: "Scalar_UWORD",
    XCPRecordLayout.Scalar_SWORD: "Scalar_SWORD",
    XCPRecordLayout.Scalar_ULONG: "Scalar_ULONG",
    XCPRecordLayout.Scalar_SLONG: "Scalar_SLONG",
    XCPRecordLayout.Scalar_A_UINT64: "Scalar_A_UINT64",
    XCPRecordLayout.Scalar_A_INT64: "Scalar_A_INT64",
    XCPRecordLayout.Scalar_FLOAT32_IEEE: "Scalar_FLOAT32_IEEE",
    # XCPRecordLayout.Scalar_FLOAT64_IEEE: "Scalar_FLOAT64_IEEE",
}
CHARACTERISTIC_CONVERSION_MAP = {
    XCPRecordLayout.Scalar_BOOLEAN: "CM_boolean",
    XCPRecordLayout.Scalar_UBYTE: "CM_uint8",
    XCPRecordLayout.Scalar_SBYTE: "CM_int8",
    XCPRecordLayout.Scalar_UWORD: "CM_uint16",
    XCPRecordLayout.Scalar_SWORD: "CM_int16",
    XCPRecordLayout.Scalar_ULONG: "CM_uint32",
    XCPRecordLayout.Scalar_SLONG: "CM_int32",
    XCPRecordLayout.Scalar_A_UINT64: "CM_uint64",
    XCPRecordLayout.Scalar_A_INT64: "CM_int64",
    XCPRecordLayout.Scalar_FLOAT32_IEEE: "CM_float32",
    # XCPRecordLayout.Scalar_FLOAT64_IEEE: "CM_float64",
}
CHARACTERISTIC_UPPER_LIMIT_MAP = {
    XCPRecordLayout.Scalar_BOOLEAN: 1,
    XCPRecordLayout.Scalar_UBYTE: 255,
    XCPRecordLayout.Scalar_SBYTE: 127,
    XCPRecordLayout.Scalar_UWORD: 65535,
    XCPRecordLayout.Scalar_SWORD: 32767,
    XCPRecordLayout.Scalar_ULONG: 4294967295,
    XCPRecordLayout.Scalar_SLONG: 2147483647,
    XCPRecordLayout.Scalar_A_UINT64: 18446744073709551615,
    XCPRecordLayout.Scalar_A_INT64: 9223372036854775807,
    XCPRecordLayout.Scalar_FLOAT32_IEEE: 3.4028234663852886e+38,
    # XCPRecordLayout.Scalar_FLOAT64_IEEE: 1.7976931348623157e+308,
}
CHARACTERISTIC_LOWER_LIMIT_MAP = {
    XCPRecordLayout.Scalar_BOOLEAN: 0,
    XCPRecordLayout.Scalar_UBYTE: 0,
    XCPRecordLayout.Scalar_SBYTE: -128,
    XCPRecordLayout.Scalar_UWORD: 0,
    XCPRecordLayout.Scalar_SWORD: -32768,
    XCPRecordLayout.Scalar_ULONG: 0,
    XCPRecordLayout.Scalar_SLONG: -2147483648,
    XCPRecordLayout.Scalar_A_UINT64: 0,
    XCPRecordLayout.Scalar_A_INT64: -9223372036854775808,
    XCPRecordLayout.Scalar_FLOAT32_IEEE: -3.4028234663852886e+38,
    # XCPRecordLayout.Scalar_FLOAT64_IEEE: -1.7976931348623157e+308,
}

MEARSUREMENT_DATA_TYPE_MAP = {
    XCPDataType.UBYTE: "UBYTE",
    XCPDataType.SBYTE: "SBYTE",
    XCPDataType.UWORD: "UWORD",
    XCPDataType.SWORD: "SWORD",
    XCPDataType.ULONG: "ULONG",
    XCPDataType.SLONG: "SLONG",
    XCPDataType.A_UINT64: "A_UINT64",
    XCPDataType.A_INT64: "A_INT64",
    XCPDataType.FLOAT32_IEEE: "FLOAT32_IEEE",
    # XCPDataType.FLOAT64_IEEE: "FLOAT64_IEEE",
}
MEARSUREMENT_CONVERSION_MAP = {
    XCPDataType.UBYTE: "CM_uint8",
    XCPDataType.SBYTE: "CM_int8",
    XCPDataType.UWORD: "CM_uint16",
    XCPDataType.SWORD: "CM_int16",
    XCPDataType.ULONG: "CM_uint32",
    XCPDataType.SLONG: "CM_int32",
    XCPDataType.A_UINT64: "CM_uint64",
    XCPDataType.A_INT64: "CM_int64",
    XCPDataType.FLOAT32_IEEE: "CM_float32",
    # XCPDataType.FLOAT64_IEEE: "CM_float64",
}
MEARSUREMENT_UPPER_LIMIT_MAP = {
    XCPDataType.UBYTE: 255,
    XCPDataType.SBYTE: 127,
    XCPDataType.UWORD: 65535,
    XCPDataType.SWORD: 32767,
    XCPDataType.ULONG: 4294967295,
    XCPDataType.SLONG: 2147483647,
    XCPDataType.A_UINT64: 18446744073709551615,
    XCPDataType.A_INT64: 9223372036854775807,
    XCPDataType.FLOAT32_IEEE: 3.4028234663852886e+38,
    # XCPDataType.FLOAT64_IEEE: 1.7976931348623157e+308,
}
MEARSUREMENT_LOWER_LIMIT_MAP = {
    XCPDataType.UBYTE: 0,
    XCPDataType.SBYTE: -128,
    XCPDataType.UWORD: 0,
    XCPDataType.SWORD: -32768,
    XCPDataType.ULONG: 0,
    XCPDataType.SLONG: -2147483648,
    XCPDataType.A_UINT64: 0,
    XCPDataType.A_INT64: -9223372036854775808,
    XCPDataType.FLOAT32_IEEE: -3.4028234663852886e+38,
    # XCPDataType.FLOAT64_IEEE: -1.7976931348623157e+308,
}

MEARSUREMENT_DATATYPE_NAME_MAP_XCP_DATATYPE = {
    "UBYTE": XCPDataType.UBYTE,
    "SBYTE": XCPDataType.SBYTE,
    "UWORD": XCPDataType.UWORD,
    "SWORD": XCPDataType.SWORD,
    "ULONG": XCPDataType.ULONG,
    "SLONG": XCPDataType.SLONG,
    "A_UINT64": XCPDataType.A_UINT64,
    "A_INT64": XCPDataType.A_INT64,
    "FLOAT32_IEEE": XCPDataType.FLOAT32_IEEE,
    # "FLOAT64_IEEE": XCPDataType.FLOAT64_IEEE,
}

CHARACTERISTIC_RECODER_LAYOUT_NAME_MAP_XCP_RECODER_LAYOUT = {
    "Scalar_BOOLEAN": XCPRecordLayout.Scalar_BOOLEAN,
    "Scalar_UBYTE": XCPRecordLayout.Scalar_UBYTE,
    "Scalar_SBYTE": XCPRecordLayout.Scalar_SBYTE,
    "Scalar_UWORD": XCPRecordLayout.Scalar_UWORD,
    "Scalar_SWORD": XCPRecordLayout.Scalar_SWORD,
    "Scalar_ULONG": XCPRecordLayout.Scalar_ULONG,
    "Scalar_SLONG": XCPRecordLayout.Scalar_SLONG,
    "Scalar_A_UINT64": XCPRecordLayout.Scalar_A_UINT64,
    "Scalar_A_INT64": XCPRecordLayout.Scalar_A_INT64,
    "Scalar_FLOAT32_IEEE": XCPRecordLayout.Scalar_FLOAT32_IEEE,
}

CHARACTERISTIC_RECODER_LAYOUT_MAP_LENGTH = {
    XCPRecordLayout.Scalar_BOOLEAN: 1,
    XCPRecordLayout.Scalar_UBYTE: 1,
    XCPRecordLayout.Scalar_SBYTE: 1,
    XCPRecordLayout.Scalar_UWORD: 2,
    XCPRecordLayout.Scalar_SWORD: 2,
    XCPRecordLayout.Scalar_ULONG: 4,
    XCPRecordLayout.Scalar_SLONG: 4,
    XCPRecordLayout.Scalar_A_UINT64: 8,
    XCPRecordLayout.Scalar_A_INT64: 8,
    XCPRecordLayout.Scalar_FLOAT32_IEEE: 4,
}

def trans_value_to_buffer_by_datatype(
    value: typing.Union[int, float, bool], 
    datatype:XCPDataType) -> typing.List[int]:
    """
    将数据基于数据类型填充到 buffer 中，并返回填充后的 buffer

    Args:
        value (typing.Union[int, float, bool]): 要填充的原始数据
        datatype (XCPDataType): 数据类型
        buffer (typing.Optional[typing.List[int]], optional): 要填充的 buffer. Defaults to None.

    Returns:
        typing.List[int]: 填充后的 buffer
    """
    res = []
    try:
        if (datatype == XCPDataType.UBYTE):
            value = int(value)
            return [byte for byte in value.to_bytes(1, byteorder="little", signed=False)]
        elif (datatype == XCPDataType.SBYTE):
            value = int(value)
            return [byte for byte in value.to_bytes(1, byteorder="little", signed=True)]
        elif (datatype == XCPDataType.UWORD):
            value = int(value)
            return [byte for byte in value.to_bytes(2, byteorder="little", signed=False)]
        elif (datatype == XCPDataType.SWORD):
            value = int(value)
            return [byte for byte in value.to_bytes(2, byteorder="little", signed=True)]
        elif (datatype == XCPDataType.ULONG):
            value = int(value)
            return [byte for byte in value.to_bytes(4, byteorder="little", signed=False)]
        elif (datatype == XCPDataType.SLONG):
            value = int(value)
            return [byte for byte in value.to_bytes(4, byteorder="little", signed=True)]
        elif (datatype == XCPDataType.A_UINT64):
            value = int(value)
            return [byte for byte in value.to_bytes(8, byteorder="little", signed=False)]
        elif (datatype == XCPDataType.A_INT64):
            value = int(value)
            return [byte for byte in value.to_bytes(8, byteorder="little", signed=True)]
        elif (datatype == XCPDataType.FLOAT32_IEEE):
            value = float(value)
            bytes_representation = struct.pack("<f", value)
            return [byte for byte in bytes_representation]
        # elif (datatype == XCPDataType.FLOAT64_IEEE):
        #     value = float(value)
        #     bytes_representation = struct.pack("<d", value)
        #     return [byte for byte in bytes_representation]
        else:
            get_logger().error("Unsupported datatype: %s", datatype)
    except Exception as e:
        get_logger().error(traceback.format_exc())
        return res
    
def trans_buffer_to_value_by_recoder_layout(
    buffer: typing.List[int], 
    recoder_layout: XCPRecordLayout) -> typing.Optional[typing.Union[int, float, bool]]:
    """
    将 buffer 转换为数据类型

    Args:
        buffer (typing.List[int]): 要转换的 buffer
        datatype (XCPDataType): 数据类型

    Returns:
        typing.Optional[typing.Union[int, float, bool]]: 转换后的数据
    """
    res = None
    try:
        if (recoder_layout == XCPRecordLayout.Scalar_BOOLEAN):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=False)
        elif (recoder_layout == XCPRecordLayout.Scalar_UBYTE):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=False)
        elif (recoder_layout == XCPRecordLayout.Scalar_SBYTE):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=True)
        elif (recoder_layout == XCPRecordLayout.Scalar_UWORD):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=False)
        elif (recoder_layout == XCPRecordLayout.Scalar_SWORD):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=True)
        elif (recoder_layout == XCPRecordLayout.Scalar_ULONG):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=False)
        elif (recoder_layout == XCPRecordLayout.Scalar_SLONG):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=True)
        elif (recoder_layout == XCPRecordLayout.Scalar_A_UINT64):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=False)
        elif (recoder_layout == XCPRecordLayout.Scalar_A_INT64):
            res = int.from_bytes(bytearray(buffer), byteorder="little", signed=True)
        elif (recoder_layout == XCPRecordLayout.Scalar_FLOAT32_IEEE):
            bytes_representation = bytes(buffer)
            res = struct.unpack("<f", bytes_representation)[0]
        # elif (recoder_layout == XCPRecordLayout.Scalar_FLOAT64_IEEE):
        #     bytes_representation = bytes(buffer)
        #     res = struct.unpack("<d", bytes_representation)[0]
        else:
            get_logger().error("Unsupported datatype: %s", datatype)
    except Exception as e:
        get_logger().error(traceback.format_exc())
    return res

def int_list_to_uint32(int_list:typing.List[int], mode:str='big') -> int:
    '''
    Convert a list of integers to a single unsigned 32-bit integer.
    parameters:
    int_list: list of integers to be converted
    mode: 'big' or 'little' endian, default is 'big'
    returns: unsigned 32-bit integer
    '''
    if mode == 'big':
        return int.from_bytes(bytearray(int_list), byteorder='big')
    elif mode == 'little':
        return int.from_bytes(bytearray(int_list), byteorder='little')
    return 0

def XCPA2lCharacteristic_to_a2l_dict(characteristic: XCPA2lCharacteristic) -> dict:
    """
    将 XCPCharacteristic 转换为 a2l json 中表达的 dict 形式

    Args:
        xcp_chatacteristic (XCPCharacteristic): _description_

    Returns:
        dict: _description_
    """
    res = {
        "Name": {
            "Value": characteristic.name
        },
        "LongIdentifier": {"Value": characteristic.long_identifier} if characteristic.long_identifier else {},
        "Type": "VALUE",
        "Address": {
            "Value": str(characteristic.address),    # 十进制字符串
            "Base": 16,
            "Size": 8
        },
        "Deposit": {
            "Value": CHARACTERISTIC_DEPOSIT_MAP[characteristic.record_layout]
        },
        "MaxDiff": {},
        "Conversion": {
            "Value": CHARACTERISTIC_CONVERSION_MAP[characteristic.record_layout]
        },
        "LowerLimit": {
            "Value": CHARACTERISTIC_LOWER_LIMIT_MAP[characteristic.record_layout] if (characteristic.lower_limit == None) else characteristic.lower_limit
        },
        "UpperLimit": {
            "Value": CHARACTERISTIC_UPPER_LIMIT_MAP[characteristic.record_layout] if (characteristic.upper_limit == None) else characteristic.upper_limit
        }
    }
    return res

def XCPA2lMearsurement_to_a2l_dict(mearsurement: XCPA2lMearsurement) -> dict:
    """
    将 XCPA2lMearsurement 转换为 a2l json 中表达的 dict 形式

    Args:
        mearsurement (XCPA2lMearsurement): _description_

    Returns:
        dict: _description_
    """

    a2l_template_mearsure = {
        "Name": {
            "Value": mearsurement.name
        },
        "LongIdentifier": {"Value": mearsurement.long_identifier} if mearsurement.long_identifier else {},
        "DataType": {
            "Value": MEARSUREMENT_DATA_TYPE_MAP[mearsurement.data_type]
        },
        "Conversion": {
            "Value": MEARSUREMENT_CONVERSION_MAP[mearsurement.data_type]
        },
        "Resolution": {
            "Base": 10,
            "Size": 1
        },
        "Accuracy": {},
        "LowerLimit": {
            "Value": MEARSUREMENT_LOWER_LIMIT_MAP[mearsurement.data_type] if (mearsurement.lower_limit == None) else mearsurement.lower_limit
        },
        "UpperLimit": {
            "Value": MEARSUREMENT_UPPER_LIMIT_MAP[mearsurement.data_type] if (mearsurement.upper_limit == None) else mearsurement.upper_limit
        },
        "ECU_ADDRESS": {
            "Address": {
            "Value": str(mearsurement.address),    # 十进制字符串
            "Base": 16,
            "Size": 8
            }
        }
    }
    return a2l_template_mearsure
    
    